/*
*
*/
package smartcontroller;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.fxmisc.easybind.EasyBind;
import com.jfoenix.controls.JFXButton;
import application.Main;
import application.settings.ApplicationSettingsController.SettingsTab;
import application.tools.ActionTool;
import application.tools.InfoTool;
import application.tools.NotificationType;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.util.Duration;
import smartcontroller.media.Audio;
import smartcontroller.media.Media;
/**
* Used to control big amounts of data in user interface.
*
* @author GOXR3PLUS
*/
public class SmartController extends StackPane {
//--------------------------------
@FXML
private BorderPane mainBorder;
@FXML
private TitledPane titledPane;
@FXML
private HBox searchBarHBox;
@FXML
private JFXButton refreshButton;
@FXML
private JFXButton showSettings;
@FXML
private HBox navigationHBox;
@FXML
private Button previous;
@FXML
private TextField pageField;
@FXML
private Button goToPage;
@FXML
private Button next;
@FXML
private MenuButton actionsMenuButton;
@FXML
private MenuItem importFolder;
@FXML
private MenuItem importFiles;
@FXML
private MenuItem exportFiles;
@FXML
private MenuItem clearAll;
@FXML
private StackPane centerStackPane;
@FXML
private Region region;
@FXML
private VBox indicatorVBox;
@FXML
private ProgressIndicator indicator;
@FXML
private Button cancel;
@FXML
private TextArea informationTextArea;
// ----------------------------------------------------------
private final Genre genre;
/**
* The name of the database table
* (eg. @see ActionTool.returnRandomTableName())
*/
private final String dataBaseTableName;
/** The name of the SmartController . */
private String controllerName;
/** Total items in database table . */
private IntegerProperty totalInDataBase = new SimpleIntegerProperty(0);
/**
* The last focus owner of the Scene , it is used by the pageField TextField
*/
private Node focusOwner;
/** The table viewer. */
private final MediaTableViewer tableViewer;
/** This list keeps all the Media Items from the TableViewer */
private final ObservableList<Media> itemsObservableList = FXCollections.observableArrayList();
/** The current page inside the TableViewer */
private IntegerProperty currentPage = new SimpleIntegerProperty(0);
/** Maximum items allowed per page. */
private int maximumPerPage = 50;
// ---------Services--------------------------
/** The search service. */
public final SmartControllerSearcher searchService;
/** The load service. */
public final LoadService loadService;
/** The input service. */
public final InputService inputService;
/** CopyOrMoveService */
public final CopyOrMoveService copyOrMoveService;
// ---------Security---------------------------
/** The deposit working. */
public volatile boolean depositWorking;
/** The un deposit working. */
public volatile boolean undepositWorking;
/** The rename working. */
public volatile boolean renameWorking;
/** The update working. */
public volatile boolean updateWorking;
// --------------------------------------------------
/**
* The Vertical ScrollBar position of SmartController TableViewer without
* the search activated
*/
private double verticalScrollValueWithoutSearch = -1;
/**
* The Vertical ScrollBar position of SmartController TableViewer when the
* the search activated
*/
private double verticalScrollValueWithSearch = -1;
/**
* Instantiates a new smart controller.
*
* @param genre
* .. @see Genre
* @param controllerName
* The name of the SmartController
* @param dataBaseTableName
* The name of the database table <br>
* ..@see ActionTool.returnRandomTableName()
*/
public SmartController(Genre genre, String controllerName, String dataBaseTableName) {
this.genre = genre;
this.controllerName = controllerName;
this.dataBaseTableName = dataBaseTableName;
// Initialize
tableViewer = new MediaTableViewer();
searchService = new SmartControllerSearcher(this);
loadService = new LoadService();
inputService = new InputService();
copyOrMoveService = new CopyOrMoveService();
// FXMLLoader
FXMLLoader loader = new FXMLLoader(getClass().getResource(InfoTool.FXMLS + "SmartController.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
/*-----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
* Initialize Method
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*/
private String previousCancelText = "";
/**
* Called as soon as FXML file has been loaded
*/
@FXML
private void initialize() {
// ------ centerStackPane
centerStackPane.setOnKeyReleased(key -> {
KeyCode code = key.getCode();
if (code == KeyCode.LEFT) {
goPrevious();
} else if (code == KeyCode.RIGHT) {
goNext();
} else if (tableViewer.getSelectedCount() > 0) { // TableViewer
if (code == KeyCode.P)
ActionTool.openFileLocation(tableViewer.getSelectionModel().getSelectedItem().getFilePath());
else if (code == KeyCode.DELETE && SmartController.this.genre != Genre.SEARCHWINDOW)
prepareDelete(key.isShiftDown());
}
});
// ------ tableViewer
centerStackPane.getChildren().add(tableViewer);
tableViewer.toBack();
// ------ region
region.setVisible(false);
// FunIndicator
// FunIndicator funIndicator = new FunIndicator();
// //super.getChildren().add(super.getChildren().size() - 1, funIndicator);
// funIndicator.setPrefSize(50, 50);
// indicatorVBox.getChildren().add(0, funIndicator);
// region.visibleProperty().addListener((observable, oldValue, newValue) -> {
// if (!region.isVisible())
// funIndicator.pause();
// else {
// funIndicator.setFromColor(Color.WHITE);
// funIndicator.start();
// }
// });
// ------ progress indicator
//funIndicator.visibleProperty().bind(region.visibleProperty());
indicator.setVisible(true);
//indicator.visibleProperty().bind(region.visibleProperty())
indicatorVBox.setVisible(false);
indicatorVBox.visibleProperty().bind(region.visibleProperty());
// ------ cancel
cancel.hoverProperty().addListener((observable , oldValue , newValue) -> cancel.setText(cancel.isHover() ? "cancel" : previousCancelText));
cancel.textProperty().addListener((observable , oldValue , newValue) -> {
if (!"cancel".equals(cancel.getText())) {
previousCancelText = cancel.getText();
//Change it if it is hovered
if (cancel.isHover())
cancel.setText("cancel");
}
});
//cancel.visibleProperty().bind(region.visibleProperty())
cancel.setVisible(true);
cancel.setDisable(true);
// ------ searchBarHBox
searchBarHBox.getChildren().add(1, searchService);
//------navigationHBox
//navigationHBox.disableProperty().bind(this.totalInDataBase.isEqualTo(0))
// ------ previous
//previous.opacityProperty()
// .bind(Bindings.when(previous.hoverProperty().or(next.hoverProperty())).then(1.0).otherwise(0.5))
//previous.disableProperty().bind(next.disabledProperty())
previous.disableProperty().bind(currentPage.isEqualTo(0));
previous.setOnAction(a -> goPrevious());
// ------- next
//next.opacityProperty()
// .bind(Bindings.when(next.hoverProperty().or(previous.hoverProperty())).then(1.0).otherwise(0.5))
next.setDisable(true);
next.setOnAction(a -> goNext());
//Handler
EventHandler<ActionEvent> handler = ac -> {
if (!pageField.getText().isEmpty() && !loadService.isRunning() && !searchService.service.isRunning() && totalInDataBase.get() != 0) {
int listNumber = Integer.parseInt(pageField.getText());
if (listNumber <= maximumList()) {
currentPage.set(listNumber);
loadService.startService(false, true);
} else {
pageField.setText(Integer.toString(listNumber));
pageField.selectEnd();
}
}
};
//-----goToPage
goToPage.setOnAction(handler);
//goToPage.disableProperty().bind(currentPage.isEqualTo(Integer.valueOf(pageField.getText())))
// -------- pageField
//pageField.opacityProperty()
// .bind(Bindings.when(pageField.hoverProperty().or(next.hoverProperty()).or(previous.hoverProperty()))
// .then(1.0).otherwise(0.03))
//pageField.disableProperty().bind(next.disabledProperty())
pageField.textProperty().addListener((observable , oldValue , newValue) -> {
if (!newValue.matches("\\d"))
pageField.setText(newValue.replaceAll("\\D", ""));
if (!pageField.getText().isEmpty()) {
// System.out.println("Setting")
int maximumPage = maximumList();
// System.out.println("maximum Page:"+maximumPage)
if (Integer.parseInt(pageField.getText()) > maximumPage)
Platform.runLater(() -> {
pageField.setText(Integer.toString(maximumPage));
pageField.selectEnd();
});
}
// System.out.println("CurrentPape:" + currentPage.get() + " , PageField:" + Integer.valueOf(pageField.getText()) + " ->"
// + currentPage.isEqualTo(Integer.valueOf(pageField.getText())).get() + " , Property:"
// + currentPage.isEqualTo(Integer.valueOf(pageField.getText())));
});
pageField.setOnAction(handler);
pageField.setOnScroll(scroll -> { // SCROLL
//Calculate the Value
int current = Integer.parseInt(pageField.getText());
if (scroll.getDeltaY() > 0 && current < maximumList())
++current;
else if (scroll.getDeltaY() < 0 && current >= 1)
--current;
// Update pageField
pageField.setText(String.valueOf(current));
pageField.selectEnd();
pageField.deselect();
});
//When the PageField is being hovered
pageField.hoverProperty().addListener(l -> {
if (!pageField.isHover())
focusOwner.requestFocus();
else {
focusOwner = Main.window.getScene().getFocusOwner();
pageField.requestFocus();
pageField.selectEnd();
}
});
//showSettings
showSettings.setOnAction(a -> Main.settingsWindow.showWindow(SettingsTab.PLAYLISTS));
//importFolder
importFolder.setOnAction(a -> {
File file = Main.specialChooser.selectFolder(Main.window);
if (file != null)
inputService.start(Arrays.asList(file));
});
// importFiles
importFiles.setOnAction(a -> {
List<File> list = Main.specialChooser.prepareToImportSongFiles(Main.window);
if (list != null && !list.isEmpty())
inputService.start(list);
});
// exportFiles
exportFiles.setOnAction(a -> Main.exportWindow.show(this));
// Export
// ...
// clearAll
clearAll.setOnAction(ac -> {
if (ActionTool.doQuestion("You want to remove all the Files from ->" + this
+ "\n\nThis of course doesn't mean that they will be deleted from your computer",Main.window))
clearDataBaseTable();
});
// -- refreshButton
refreshButton.setOnAction(e -> loadService.startService(false, true));
// Update
updateLabel();
//---------------------Check the genre--------------------
if (genre == Genre.SEARCHWINDOW) {
navigationHBox.setVisible(false);
actionsMenuButton.setVisible(false);
navigationHBox.setManaged(false);
actionsMenuButton.setManaged(false);
}
}
/**
* Changes the MaximumPerPage
*
* @param newMaximumPerPage
* @param updateSmartController
* If true the loadService will start (Memory consuming ;( ) use with
* great care
*/
public void setNewMaximumPerPage(int newMaximumPerPage , boolean updateSmartController) {
if (maximumPerPage == newMaximumPerPage)
return;
//Change it
currentPage.set( ( maximumPerPage == 50 ) ? currentPage.get() / 2 : currentPage.get() * 2 + ( currentPage.get() % 2 == 0 ? 0 : 1 ));
maximumPerPage = newMaximumPerPage;
if (updateSmartController && isFree(false))
loadService.startService(false, true);
}
/*-----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* METHODS
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*/
/**
* Prepares the delete operation when more than one Media files will be
* deleted.
*
* @param permanent
* <br>
* true->storage medium + (play list)/library<br>
* false->only from (play list)/library
* @param controller
* the controller
*/
public void prepareDelete(boolean permanent) {
int previousTotal = getTotalInDataBase();
// Remove selected items
removeSelected(permanent);
// Update
if (previousTotal != getTotalInDataBase()) {
// if (genre == Genre.LIBRARYMEDIA)
// Main.libraryMode.multipleLibs.getSelectedLibrary().updateSettingsTotalLabel();
loadService.startService(true, true, true);
}
}
/**
* Removes the selected songs.
*
* @param permanent
* <br>
* true->storage medium + (play list)/library false->only from (play
* list)/library<br>
*/
public void removeSelected(boolean permanent) {
// Free? && How many items are selected?+Question
if (isFree(true) && tableViewer.getSelectedCount() == 1
? ActionTool.doDeleteQuestion(permanent, tableViewer.getSelectionModel().getSelectedItem().getFileName(),
tableViewer.getSelectedCount(),Main.window)
: ActionTool.doDeleteQuestion(permanent, Integer.toString(tableViewer.getSelectedCount()), tableViewer.getSelectedCount(),Main.window)) {
// Remove selected items
if (genre == Genre.SEARCHWINDOW)
//Call the delete for each selected item
tableViewer.getSelectionModel().getSelectedItems().iterator().forEachRemaining(r -> r.delete(permanent, false, false, this, null));
else
try (PreparedStatement preparedDelete = Main.dbManager.getConnection()
.prepareStatement("DELETE FROM '" + dataBaseTableName + "' WHERE PATH=?")) {
//Call the delete for each selected item
tableViewer.getSelectionModel().getSelectedItems().iterator()
.forEachRemaining(r -> r.delete(permanent, false, false, this, preparedDelete));
// Library?
// if (genre == Genre.LIBRARYMEDIA)
// Main.libraryMode.updateLibraryTotalLabel(controllerName);
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
}
/**
* Clears all the items from this library *.
*/
private void clearDataBaseTable() {
if (!isFree(true))
return;
// Security Value
undepositWorking = true;
// Controller
getIndicator().setProgress(-1);
getCancelButton().setText("Clearing...");
getRegion().setVisible(true);
// New Thread
new Thread(() -> {
try {
Main.dbManager.getConnection().createStatement().executeUpdate("DELETE FROM '" + dataBaseTableName + "'");
Main.dbManager.commit();
Platform.runLater(() -> {
getRegion().setVisible(false);
getCancelButton().setText("Cancel");
});
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
} finally {
undepositWorking = false;
}
}).start();
simpleClear();
// Library?
// if (genre == Genre.LIBRARYMEDIA)
// Main.libraryMode.updateLibraryTotalLabel(controllerName);
}
/**
* Updates the label of the smart controller. [[SuppressWarningsSpartan]]
*/
public void updateLabel() {
if (searchService.isActive() || genre == Genre.SEARCHWINDOW)
titledPane.setText(
"[Found: <" + itemsObservableList.size() + "> first matching] from [ Total:<" + InfoTool.getNumberWithDots(totalInDataBase.get())
+ "> MaxPerPage:<" + maximumPerPage + "> ] Selected:" + tableViewer.getSelectedCount());
else
titledPane.setText("[Total:<" + InfoTool.getNumberWithDots(totalInDataBase.get()) + "> MaxPerPage:<" + maximumPerPage + "> CurrentPage:<"
+ InfoTool.getNumberWithDots(currentPage.get()) + "> MaxPage:<" + InfoTool.getNumberWithDots(maximumList()) + ">] [ Selected:"
+ tableViewer.getSelectedCount() + " Showing:" + InfoTool.getNumberWithDots(maximumPerPage * currentPage.get()) + "-"
+ InfoTool.getNumberWithDots(maximumPerPage * currentPage.get() + itemsObservableList.size()) + " ]");
pageField.setText(Integer.toString(currentPage.get()));
}
/**
* Checks if any updates are on progress in the controller.
*
* @param showMessage
* the show message
* @return true->if yes<br>
* false->if not
*/
public boolean isFree(boolean showMessage) {
boolean isFree = true;
String message = null;
if (depositWorking) {
isFree = false;
message = "Depositing";
} else if (undepositWorking) {
isFree = false;
message = "Undepositing";
} else if (searchService.service.isRunning()) {
isFree = false;
message = "Searching";
} else if (renameWorking) {
isFree = false;
message = "Renaming";
} else if (updateWorking) {
isFree = false;
message = "Updating";
} else if (copyOrMoveService.isRunning()) {
isFree = false;
message = "Copy-Move Service";
}
if (!isFree && showMessage)
showMessage(message);
return isFree;
}
/**
* Gets the region.
*
* @return the region
*/
public Region getRegion() {
return region;
}
/**
* Gets the indicator.
*
* @return the indicator
*/
public ProgressIndicator getIndicator() {
return indicator;
}
/**
* Gets the cancel button.
*
* @return the cancel button
*/
public Button getCancelButton() {
return cancel;
}
/**
* Gets the next button.
*
* @return the next button
*/
public HBox getNavigationHBox() {
return navigationHBox;
}
/**
* Gets the next button.
*
* @return the next button
*/
public Button getNextButton() {
return next;
}
/**
* Gets the previous button.
*
* @return the previous button
*/
public Button getPreviousButton() {
return previous;
}
/**
* Gets the data base table name.
*
* @return the data base table name
*/
public String getDataBaseTableName() {
return dataBaseTableName;
}
/**
* Show message.
*
* @param reason
* the reason
*/
private void showMessage(String reason) {
ActionTool.showNotification("Message", "[" + reason + "] is working on:\n " + toString() + "\n\t retry as soon as it finish.",
Duration.millis(2000), NotificationType.INFORMATION);
}
/**
* Unbind.
*/
public void unbind() {
region.visibleProperty().unbind();
region.setVisible(false);
indicator.progressProperty().unbind();
}
/**
* Goes on the Previous List.
*/
public void goPrevious() {
if (SmartController.this.genre != Genre.SEARCHWINDOW && isFree(false) && !searchService.isActive() && totalInDataBase.get() != 0
&& currentPage.get() > 0) {
currentPage.set(currentPage.get() - 1);
loadService.startService(false, true);
}
}
/**
* Goes on the Next List.
*/
public void goNext() {
if (SmartController.this.genre != Genre.SEARCHWINDOW && isFree(false) && !searchService.isActive() && totalInDataBase.get() != 0
&& currentPage.get() < maximumList()) {
currentPage.set(currentPage.get() + 1);
loadService.startService(false, true);
}
}
/**
* Updates the List.
*/
protected void updateList() {
if (totalInDataBase.get() != 0)
next.setDisable(! ( currentPage.isEqualTo(0).or(currentPage.lessThan(maximumList())).get() && maximumList() != 0 ));
else {
next.setDisable(true);
currentPage.set(0);
}
// update the label
updateLabel();
// refresh the tableViewer
tableViewer.refresh();
if (!tableViewer.getSortOrder().isEmpty())
tableViewer.sort();
}
/**
* Clear all the items from list.
*/
private void simpleClear() {
itemsObservableList.clear();
totalInDataBase.set(0);
updateList();
}
/**
* Sets the name.
*
* @param newName
* the new name
*/
public void setName(String newName) {
controllerName = newName;
}
/**
* Returns the name of the smart controller
*
* @return The name of the smartController
*/
public String getName() {
return controllerName;
}
@Override
public String toString() {
return "PlayList: <" + controllerName + ">";
}
/**
* Returns Marked Songs.
*
* @return the selected items
*/
public ObservableList<Media> getSelectedItems() {
return tableViewer.getSelectionModel().getSelectedItems();
}
/**
* Return the number of the final List counting from <b>firstList->0
* SecondList->1 ....</b>
*
* @return the int
*/
public int maximumList() {
return totalInDataBase.get() == 0 ? 0
: ( totalInDataBase.get() / maximumPerPage ) + ( ( totalInDataBase.get() % maximumPerPage == 0 ) ? -1 : 0 );
}
/**
* Indicates that a capture event has been fired to this controller from the
* CaptureWindow.
*
* @param array
* the array
*/
public void fireCaptureEvent(int[] array) {
// Bounds bounds
/*
* for (ButtonBase song : bigList) { bounds =
* song.localToScreen(song.getBoundsInLocal()); // button rectangle
* overlaps capture rectangle ? if (bounds.getMinX() <= array[0] +
* array[2] && bounds.getMaxX() >= array[0] && bounds.getMinY() <=
* array[1] + array[3] && bounds.getMaxY() >= array[1]) ((Audio)
* song).setMarked(true, false); else ((Audio) song).setMarked(false,
* false); }
*/
updateLabel();
}
/**
* Gets the total in data base.
*
* @return the total in data base
*/
public int getTotalInDataBase() {
return totalInDataBase.get();
}
/**
* Sets the total in data base.
*
* @param totalInDataBase
* the new total in data base
*/
public void setTotalInDataBase(int totalInDataBase) {
this.totalInDataBase.set(totalInDataBase);
}
/**
* Total in data base property.
*
* @return the integer property
*/
public IntegerProperty totalInDataBaseProperty() {
return totalInDataBase;
}
/**
* @return the currentPage
*/
public IntegerProperty getCurrentPage() {
return currentPage;
}
/**
* @param currentPage
* the currentPage to set
*/
public void setCurrentPage(IntegerProperty currentPage) {
this.currentPage = currentPage;
}
/**
* @return the maximumPerPage
*/
public int getMaximumPerPage() {
return maximumPerPage;
}
/**
* @return the indicatorVBox
*/
public VBox getIndicatorVBox() {
return indicatorVBox;
}
/**
* @return the genre
*/
public Genre getGenre() {
return genre;
}
/**
* @return the tableViewer
*/
public MediaTableViewer getTableViewer() {
return tableViewer;
}
/**
* @return the itemsObservableList
*/
public ObservableList<Media> getItemsObservableList() {
return itemsObservableList;
}
/**
* @return the informationTextArea
*/
public TextArea getInformationTextArea() {
return informationTextArea;
}
/**
* @param informationTextArea
* the informationTextArea to set
*/
public void setInformationTextArea(TextArea informationTextArea) {
this.informationTextArea = informationTextArea;
}
/**
* Calculates the total entries in the database table [it MUST be called
* from external thread cause it may lag the application ]
*/
public synchronized void calculateTotalEntries() {
// calculate the total entries
if (getTotalInDataBase() == 0)
try (ResultSet s = Main.dbManager.getConnection().createStatement()
.executeQuery("SELECT COUNT(*) FROM '" + getDataBaseTableName() + "';")) {
//Total items
final int total = s.getInt(1);
//Update the total
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
setTotalInDataBase(total);
//Count Down
latch.countDown();
});
//Wait
latch.await();
} catch (SQLException | InterruptedException ex) {
ex.printStackTrace();
}
}
/*-----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* Table Viewer
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*/
/**
* @return the verticalScrollValueWithoutSearch
*/
public double getVerticalScrollValueWithoutSearch() {
return verticalScrollValueWithoutSearch;
}
/**
* @param verticalScrollValueWithoutSearch
* the verticalScrollValueWithoutSearch to set
*/
public void setVerticalScrollValueWithoutSearch(double verticalScrollValueWithoutSearch) {
this.verticalScrollValueWithoutSearch = verticalScrollValueWithoutSearch;
}
/**
* @return the verticalScrollValueWithSearch
*/
public double getVerticalScrollValueWithSearch() {
return verticalScrollValueWithSearch;
}
/**
* @param verticalScrollValueWithSearch
* the verticalScrollValueWithSearch to set
*/
public void setVerticalScrollValueWithSearch(double verticalScrollValueWithSearch) {
this.verticalScrollValueWithSearch = verticalScrollValueWithSearch;
}
/**
* Representing the data of SmartController.
*
* @author GOXR3PLUS
*/
public class MediaTableViewer extends TableView<Media> {
/** The has been played. */
@FXML
private TableColumn<Media,SimpleObjectProperty<ImageView>> hasBeenPlayed;
/** The media type. */
@FXML
private TableColumn<Media,SimpleObjectProperty<ImageView>> mediaType;
/** The title. */
@FXML
private TableColumn<Media,String> title;
/** The duration. */
@FXML
private TableColumn<Media,String> duration;
/** The times played. */
@FXML
private TableColumn<Media,Integer> timesPlayed;
/** The stars. */
@FXML
private TableColumn<Media,Double> stars;
/** The hour imported. */
@FXML
private TableColumn<Media,String> hourImported;
/** The date imported. */
@FXML
private TableColumn<Media,String> dateImported;
/** The date that the file was created */
@FXML
private TableColumn<Media,String> dateFileCreated;
/** The date that the file was last modified */
@FXML
private TableColumn<Media,String> dateFileModified;
/** It is a remix? */
@FXML
private TableColumn<?,?> remix;
/** The album. */
@FXML
private TableColumn<?,?> album;
/** The composer. */
@FXML
private TableColumn<?,?> composer;
/** The comment. */
@FXML
private TableColumn<?,?> comment;
/** The genre. */
@FXML
private TableColumn<?,?> genre;
/** The bpm. */
@FXML
private TableColumn<?,?> bpm;
/** The key. */
@FXML
private TableColumn<?,?> key;
/** The harmonic. */
@FXML
private TableColumn<?,?> harmonic;
/** The bit rate. */
@FXML
private TableColumn<?,?> bitRate;
/** The year. */
@FXML
private TableColumn<?,?> year;
/** The drive. */
@FXML
private TableColumn<Media,String> drive;
/** The file path. */
@FXML
private TableColumn<Media,String> filePath;
/** The file name. */
@FXML
private TableColumn<Media,String> fileName;
/** The file type. */
@FXML
private TableColumn<Media,String> fileType;
/** The file size. */
@FXML
private TableColumn<Media,String> fileSize;
/** The album art. */
@FXML
private TableColumn<?,?> albumArt;
/** The singer. */
@FXML
private TableColumn<?,?> singer;
/** The image. */
WritableImage image = new WritableImage(100, 100);
/** The canvas. */
Canvas canvas = new Canvas();
/**
* Constructor.
*/
public MediaTableViewer() {
canvas.setWidth(100);
canvas.setHeight(100);
// FXMLLOADRE
FXMLLoader loader = new FXMLLoader(getClass().getResource(InfoTool.FXMLS + "MediaTableViewer.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException ex) {
Main.logger.log(Level.WARNING, "MediaTableViewer falied to initialize fxml..", ex);
}
}
/**
* Called as soon as .fxml has been initialized
*/
@FXML
private void initialize() {
//------------------------------TableViewer---------------------------
setItems(getItemsObservableList());
//Collect the correct
if (SmartController.this.genre == Genre.LIBRARYMEDIA)
setPlaceholder(new Label("Drag && Drop or Import/Paste Media..."));
else if (SmartController.this.genre == Genre.SEARCHWINDOW)
setPlaceholder(new Label("Search Media from all the playlists..."));
//--Selection Model
getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
getSelectionModel().getSelectedIndices().addListener((ListChangeListener<? super Integer>) l -> updateLabel()); // Main.amazon.updateInformation((Media) newValue)
//--KeyListener
setOnKeyReleased(key -> {
if ( ( key.isControlDown() || key.getCode() == KeyCode.COMMAND ) && key.getCode() == KeyCode.C) {
System.out.println("Control+C was released");
//Get Native System ClipBoard
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent content = new ClipboardContent();
// PutFiles
content.putFiles(
getSelectionModel().getSelectedItems().stream().map(s -> new File(s.getFilePath())).collect(Collectors.toList()));
//Set the Content
clipboard.setContent(content);
ActionTool.showNotification("Copied to Clipboard",
"Files copied to clipboard,you can paste them anywhere on the your system.\nFor example in Windows with [CTRL+V], in Mac[COMMAND+V]",
Duration.seconds(3.5), NotificationType.INFORMATION);
} else if (SmartController.this.genre == Genre.LIBRARYMEDIA
&& ( ( key.isControlDown() || key.getCode() == KeyCode.COMMAND ) && key.getCode() == KeyCode.V )) {
System.out.println("Control+V was released");
//Get Native System ClipBoard
final Clipboard clipboard = Clipboard.getSystemClipboard();
// Has Files? + isFree()?
if (clipboard.hasFiles() && isFree(true))
inputService.start(clipboard.getFiles());
}
});
//--Row Factory
setRowFactory(rf -> {
TableRow<Media> row = new TableRow<>();
// use EasyBind to access the valueProperty of the itemProperty
// of the cell:
row.disableProperty().bind(
// start at itemProperty of row
EasyBind.select(row.itemProperty())
// map to fileExistsProperty[a boolean] of item,
// if item non-null
.selectObject(Media::fileExistsProperty)
// map to BooleanBinding checking if false
.map(x -> !x.booleanValue())
// value to use if item was null
.orElse(false));
//Mouse Listener
row.setFocusTraversable(true);
row.setOnMouseReleased(m -> {
//We don't need null rows (rows without items)
if (row.itemProperty().getValue() != null) {
if (m.getButton() == MouseButton.SECONDARY && !row.isDisable())
getTableViewer().getSelectionModel().select(row.getIndex());
//Primary
if (m.getButton() == MouseButton.PRIMARY) {
if (m.getClickCount() == 2)
row.itemProperty().get().rename(SmartController.this, row);
} //Secondary
else if (m.getButton() == MouseButton.SECONDARY && !getTableViewer().getSelectionModel().getSelectedItems().isEmpty())
Main.songsContextMenu.showContextMenu(row.itemProperty().get(), SmartController.this.getGenre(), m.getScreenX(),
m.getScreenY(), SmartController.this, row);
}
});
//Needs fixing!!!
//KeyListener
row.setOnKeyReleased(k -> {
System.out.println("Key Released....");
KeyCode code = k.getCode();
if (code == KeyCode.R)
row.itemProperty().get().rename(SmartController.this, row);
else if (code == KeyCode.S)
getTableViewer().getSelectionModel().getSelectedItem().updateStars(SmartController.this, row);
});
// it's also possible to do this with the standard API, but
// there are lots of
// superfluous warnings sent to standard out:
// row.setStyle("-fx-background-color:red");
// row.disableProperty().bind(
// Bindings.selectBoolean(row.itemProperty(),
// "fileExists").not());
return row;
});
// --Drag Detected
setOnDragDetected(event -> {
if (getSelectedCount() != 0 && event.getScreenY() > localToScreen(getBoundsInLocal()).getMinY() + 30) {
/* allow copy transfer mode */
Dragboard db = startDragAndDrop(TransferMode.COPY, TransferMode.LINK);
/* put a string on drag board */
ClipboardContent content = new ClipboardContent();
// PutFiles
content.putFiles(
getSelectionModel().getSelectedItems().stream().map(s -> new File(s.getFilePath())).collect(Collectors.toList()));
// Single Drag and Drop ?
if (content.getFiles().size() == 1)
getSelectionModel().getSelectedItem().setDragView(db);
// Multiple Drag and Drop ?
else {
ActionTool.paintCanvas(canvas.getGraphicsContext2D(), "(" + content.getFiles().size() + ")Items", 100, 100);
db.setDragView(canvas.snapshot(null, image), 50, 0);
}
db.setContent(content);
}
event.consume();
});
if (SmartController.this.genre == Genre.LIBRARYMEDIA) {
// --Drag Over
setOnDragOver(dragOver -> {
// System.out.println(over.getGestureSource() + "," +
// controller.tableViewer)
// // Check if the drag come from the same source
// String gestureSourceString
// if (over.getGestureSource() != null)
// gestureSourceString = over.getGestureSource()
// .toString()
// else
// gestureSourceString = "null"
// The drag must come from source other than the owner
if (dragOver.getDragboard().hasFiles() && dragOver.getGestureSource() != getTableViewer()) {
dragOver.acceptTransferModes(TransferMode.LINK);
}
});
//Drag Entered and Exited
//setOnDragEntered(d -> navigationHBox.setVisible(false))
//setOnDragExited(d -> navigationHBox.setVisible(true))
// --Drag Dropped
setOnDragDropped(drop -> {
// Has Files? + isFree()?
if (drop.getDragboard().hasFiles() && isFree(true))
inputService.start(drop.getDragboard().getFiles());
drop.setDropCompleted(true);
});
}
// setOnDragDone(d -> {
// System.out.println(
// "Drag Done,is drop completed?" + d.isDropCompleted() + " , is
// accepted?" + d.isAccepted());
// System.out.println("Accepted Mode:" +
// d.getAcceptedTransferMode());
// System.out.println(" Target:" + d.getTarget() + " Gestoure
// Target:" + d.getGestureTarget());
// });
//--------------------------Other-----------------------------------
String center = "-fx-alignment:CENTER-LEFT;";
// hasBeenPlayed
hasBeenPlayed.setCellValueFactory(new PropertyValueFactory<>("hasBeenPlayed"));
// hasBeenPlayed
mediaType.setCellValueFactory(new PropertyValueFactory<>("mediaType"));
// title
title.setStyle(center);
title.setCellValueFactory(new PropertyValueFactory<>("title"));
// hourImported
hourImported.setCellValueFactory(new PropertyValueFactory<>("hourImported"));
// dateImported
dateImported.setCellValueFactory(new PropertyValueFactory<>("dateImported"));
// dateFileCreated
dateFileCreated.setCellValueFactory(new PropertyValueFactory<>("dateFileCreated"));
// dateFileCreated
dateFileModified.setCellValueFactory(new PropertyValueFactory<>("dateFileModified"));
// stars
stars.setCellValueFactory(new PropertyValueFactory<>("stars"));
// timesHeard
timesPlayed.setCellValueFactory(new PropertyValueFactory<>("timesPlayed"));
// duration
duration.setCellValueFactory(new PropertyValueFactory<>("durationEdited"));
// drive
drive.setCellValueFactory(new PropertyValueFactory<>("drive"));
// filePath
filePath.setStyle(center);
filePath.setCellValueFactory(new PropertyValueFactory<>("filePath"));
// fileName
fileName.setStyle(center);
fileName.setCellValueFactory(new PropertyValueFactory<>("fileName"));
// fileType
fileType.setCellValueFactory(new PropertyValueFactory<>("fileType"));
// fileType
fileSize.setCellValueFactory(new PropertyValueFactory<>("fileSize"));
}
/**
* Calculates the selected items in the table.
*
* @return An int representing the total selected items in the table
*/
public int getSelectedCount() {
return getTableViewer().getSelectionModel().getSelectedItems().size();
}
}
/**
* @return The Vertical ScrollBar of TableViewer
*/
public Optional<ScrollBar> getVerticalScrollBar() {
return Optional.ofNullable((ScrollBar) getTableViewer().lookup(".scroll-bar:vertical"));
}
/**
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* Load Service
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*/
public class LoadService extends Service<Void> {
/** The commit. */
private boolean commit;
/** The request focus. */
private boolean requestFocus;
/**
* Constructor.
*/
public LoadService() {
setOnSucceeded(s -> done());
setOnFailed(f -> done());
setOnCancelled(c -> done());
}
/**
* Stars the reload Service.
*
* @param commit1
* the commit
* @param requestFocus1
* the request focus
*/
public void startService(boolean commit1 , boolean requestFocus1) {
if (isRunning() || !isFree(false))
return;
// Variables
this.requestFocus = requestFocus1;
this.commit = commit1;
// Hide ContextMenu
Main.songsContextMenu.hide();
// Start
try {
// Search + Trick for genre.SearchWindow
if (searchService.isActive() || genre == Genre.SEARCHWINDOW)
searchService.service.search();
// Reload
else {
updateWorking = true;
region.visibleProperty().bind(runningProperty());
indicator.progressProperty().bind(progressProperty());
cancel.setText("Updating...");
getInformationTextArea().setText("\n Updating the playlist....");
getItemsObservableList().clear();
super.reset();
super.start();
}
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
/**
* Stars the reload Service.
*
* @param commit1
* the commit
* @param requestFocus1
* the request focus
* @param rememberScrollPosition
* Remembers the scroll position of the playlist
*/
public void startService(boolean commit1 , boolean requestFocus1 , boolean rememberScrollPosition) {
//Remember the scroll position
if (rememberScrollPosition) {
// Search is activated?
if (searchService.isActive() || genre == Genre.SEARCHWINDOW) {
// setVerticalScrollValueWithSearch(getVerticalScrollBar().getValue());
} else
getVerticalScrollBar().ifPresent(scrollBar -> setVerticalScrollValueWithoutSearch(scrollBar.getValue()));
}
startService(commit1, requestFocus1);
}
/**
* Done.
*/
// Work done
public void done() {
commit = false;
updateList();
unbind();
updateWorking = false;
if (requestFocus)
centerStackPane.requestFocus();
try {
//Fix the vertical scroll bar position
if (searchService.isActive() || genre == Genre.SEARCHWINDOW) {
System.out.println("Search is active");
getVerticalScrollBar().ifPresent(scrollBar -> scrollBar.setValue(getVerticalScrollValueWithSearch()));
setVerticalScrollValueWithSearch(0.0);
} else {
getVerticalScrollBar().ifPresent(scrollBar -> scrollBar.setValue(getVerticalScrollValueWithoutSearch()));
setVerticalScrollValueWithoutSearch(0.0);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
// counter
int counter = 0;
// // calculate the total entries
calculateTotalEntries();
// when the final list is deleted then the controller
// has to go to the previous list automatically
if (getTotalInDataBase() != 0 && getCurrentPage().get() > maximumList())
getCurrentPage().set(getCurrentPage().get() - 1);
// Select the available Media Files
String query = "SELECT* FROM '" + dataBaseTableName + "' LIMIT " + getMaximumPerPage() + " OFFSET "
+ getCurrentPage().get() * getMaximumPerPage();
try (ResultSet resultSet = Main.dbManager.getConnection().createStatement().executeQuery(query);
ResultSet dbCounter = Main.dbManager.getConnection().createStatement().executeQuery(query)) {
// Count how many items the result returned...
int currentMaximumPerList = 0;
while (dbCounter.next())
++currentMaximumPerList;
// Fetch the items from the database
List<Media> array = new ArrayList<>();
for (Audio song = null; resultSet.next();) {
song = new Audio(resultSet.getString("PATH"), resultSet.getDouble("STARS"), resultSet.getInt("TIMESPLAYED"),
resultSet.getString("DATE"), resultSet.getString("HOUR"), getGenre());
array.add(song);
//Update the progress
updateProgress(++counter, currentMaximumPerList);
}
// Add the the items to the observable list
CountDownLatch countDown = new CountDownLatch(1);
Platform.runLater(() -> {
getItemsObservableList().addAll(array);
countDown.countDown();
});
countDown.await();
//}
// commit?
if (commit)
Main.dbManager.commit();
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
}
return null;
}
};
}
}
/*-----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* Copy or Move Service
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*/
/**
* Copy or Move items
*
* @author GOXR3PLUS
*
*/
public class CopyOrMoveService extends Service<Boolean> {
File destinationFolder;
int count;
int total;
String filePath;
Operation operation;
List<File> directories;
/**
* Constructor
*/
public CopyOrMoveService() {
setOnSucceeded(s -> {
done();
ActionTool.showNotification("Message", operation + " successfully done for:\n\t" + SmartController.this, Duration.millis(1500),
NotificationType.SIMPLE);
});
setOnFailed(f -> {
done();
ActionTool.showNotification("Message", operation + " failed for:\n\t" + SmartController.this, Duration.millis(1500),
NotificationType.ERROR);
});
setOnCancelled(c -> done());
}
/**
* Copying process
*
* @param directories1
*/
public void startCopy(List<File> directories1) {
if (isRunning() || !isFree(true))
ActionTool.showNotification("Message", "Copy can't start!!", Duration.millis(2000), NotificationType.WARNING);
else {
this.directories = directories1;
commonOperations(Operation.COPY);
}
}
/**
* Moving process
*
* @param directories1
*/
public void startMoving(List<File> directories1) {
if (isRunning() || !isFree(true))
ActionTool.showNotification("Message", "Moving can't start!!", Duration.millis(2000), NotificationType.WARNING);
else {
this.directories = directories1;
commonOperations(Operation.MOVE);
}
}
/**
* Common operations on (move and copy) processes
*/
private void commonOperations(Operation operation1) {
this.operation = operation1;
// The choosen directories
destinationFolder = directories.get(0);
directories.forEach(directory -> directory.mkdir());
// Bindings
region.visibleProperty().bind(runningProperty());
indicator.progressProperty().bind(progressProperty());
cancel.setText("Exporting...");
cancel.setDisable(false);
cancel.setOnAction(e -> {
super.cancel();
cancel.setDisable(true);
});
getInformationTextArea().setText("\n Exporting Media from PlayList....");
// start
this.reset();
this.start();
}
/**
* Process has been done
*/
private void done() {
cancel.setDisable(true);
unbind();
}
@Override
protected Task<Boolean> createTask() {
return new Task<Boolean>() {
@Override
protected Boolean call() throws Exception {
try {
count = 0;
// total = (int) observableList.stream().filter(button
// -> ( (Audio) button ).isMarked()).count();
total = getItemsObservableList().size();
// Multiple Items have been selected
if (total > 0) {
// Stream
Stream<Media> stream = getItemsObservableList().stream();
stream.forEach(media -> {
if (isCancelled())
stream.close();
else {
passItem(media);
updateProgress(++count, total);
}
});
// User has pressed right click or a shortcut so one
// item has passed
}
// } else {
// passItem(Main.songsContextMenu.getM);
//
// // updateProgress
// updateProgress(1, 1);
// }
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}
/**
* Pass the media to the controller
*
* @param media
*/
private void passItem(Media media) {
filePath = ( (Audio) media ).getFilePath();
if (!new File(filePath).exists())
return;
//Useful
String source = filePath;
String destination = destinationFolder + File.separator + media.getFileName();
//Go
if (operation == Operation.COPY) {
Platform.runLater(() -> getInformationTextArea().appendText("\n Copying ->" + media.getFileName()));
ActionTool.copy(source, destination);
} else {
Platform.runLater(() -> getInformationTextArea().appendText("\n Moving ->" + media.getFileName()));
ActionTool.move(source, destination);
}
}
};
}
}
/*-----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* -----------------------------------------------------------------------
*
*
* InputService
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*
* -----------------------------------------------------------------------
*/
// TODO When importing files from external disk they are not added properlly
/**
* Manages the input operations of the SmartController.
*
* @author GOXR3PLUS
*/
public class InputService extends Service<Void> {
/** The list. */
private List<File> list;
/** The job. */
private String job;
/** The counter. */
private int progress;
/** The total files. */
private int totalFiles;
//int batchcount
//int batchSize
/**
* Constructor.
*/
public InputService() {
setOnSucceeded(s -> done());
setOnCancelled(c -> done());
setOnFailed(c -> done());
}
/**
* Start the Service.
*
* @param list1
* the list
*/
public void start(List<File> list1) {
//Check if can enter...
if (!Platform.isFxApplicationThread() || !isFree(true) || isRunning())
return;
// Security
job = "upload from system";
// We need only directories or media files
this.list = list1.stream().filter(file -> file.isDirectory() || ( file.isFile() && InfoTool.isAudioSupported(file.getAbsolutePath()) ))
.collect(Collectors.toList());
depositWorking = true;
// System.out.println(this.list)
//Clear the text of imformation text field
getInformationTextArea().clear();
// Binds
getRegion().visibleProperty().bind(runningProperty());
getIndicator().progressProperty().bind(progressProperty());
getCancelButton().setDisable(false);
getCancelButton().setText("Counting...");
getCancelButton().setOnAction(e -> {
super.cancel();
getCancelButton().setDisable(true);
});
// ....
reset();
start();
}
/**
* When the work is done.
*/
private void done() {
list = null;
unbind();
getCancelButton().setDisable(true);
depositWorking = false;
loadService.startService(true, true);
}
/*
* (non-Javadoc)
* @see javafx.concurrent.Service#createTask()
*/
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
totalFiles = progress = 0;
String date = InfoTool.getCurrentDate() , time = InfoTool.getLocalTime();
// Update informationTextArea
Platform.runLater(() -> getInformationTextArea().appendText("\nCounting files from ....\n"));
//Initialize the prepared statement
try (PreparedStatement preparedInsert = Main.dbManager.getConnection().prepareStatement(
"INSERT OR IGNORE INTO '" + dataBaseTableName + "' (PATH,STARS,TIMESPLAYED,DATE,HOUR) VALUES (?,?,?,?,?)")) {
// Start the insert work
if ("upload from system".equals(job)) {
//Count the total files to be inserted
for (File file : list) {
//File exists?
if (!file.exists())
continue;
// Update informationTextArea
Platform.runLater(() -> getInformationTextArea()
.appendText( ( !file.isDirectory() ? "File" : "Folder" ) + ": " + file.getName()));
int previousTotal = totalFiles;
// File or Folder exists?
if (isCancelled())
break;
totalFiles += countFiles(file);
// Update informationTextArea
Platform.runLater(
() -> getInformationTextArea().appendText("\n\t-> Total: [ " + ( totalFiles - previousTotal ) + " ]\n"));
}
// System.out.println("Total Files are->" + totalFiles)
//Calculate the batch size
// if (totalFiles < 20_000)
// batchSize = 1000;
// else if (totalFiles < 100_000)
// batchSize = 5000;
// else
// batchSize = 10_000;
//
// batchcount = 0;
// Update informationTextArea and cancel button
Platform.runLater(() -> {
getCancelButton().setText("Inserting...");
getInformationTextArea().appendText("\nInserting: [ " + totalFiles + " ] Files...\n");
});
for (File file : list)
if (file.exists() && !isCancelled())
try {
Files.walkFileTree(Paths.get(file.getPath()),
new HashSet<FileVisitOption>(Arrays.asList(FileVisitOption.FOLLOW_LINKS)), Integer.MAX_VALUE,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file , BasicFileAttributes attrs) throws IOException {
// System.out.println("Adding...."+s.toString())
// cancelled?
//if (isCancelled())
// paths.close();
// supported?
if (InfoTool.isAudioSupported(file + ""))
insertMedia(file + "", 0, 0, date, time, preparedInsert);
// // Update informationTextArea
// File f = path.toFile();
// if (f.isDirectory())
// Platform.runLater(() -> informationTextArea.appendText("Folder: " + f.getName() + "\n"));
// update progress
updateProgress(++progress, totalFiles);
return isCancelled() ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file , IOException e) throws IOException {
System.err.printf("Visiting failed for %s\n", file);
return FileVisitResult.SKIP_SUBTREE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir , BasicFileAttributes attrs)
throws IOException {
return isCancelled() ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
}
// try (Stream<Path> paths = Files.walk(Paths.get(file.getPath()))) {
// paths.forEach(path -> {
//
// // System.out.println("Adding...."+s.toString())
//
// // cancelled?
// if (isCancelled())
// paths.close();
//
// // supported?
// else if (InfoTool.isAudioSupported(path + ""))
// insertMedia(path + "", 0, 0, date, time, preparedInsert);
//
// // // Update informationTextArea
// // File f = path.toFile();
// // if (f.isDirectory())
// // Platform.runLater(() -> informationTextArea.appendText("Folder: " + f.getName() + "\n"));
//
// // update progress
// updateProgress(++progress, totalFiles);
// });
// } catch (IOException ex) {
// Main.logger.log(Level.WARNING, "", ex);
// }
}
saveInDataBase(preparedInsert);
} catch (Exception ex) {
ex.printStackTrace();
//Platform.runLater(() -> ActionTool.showNotification("Error", ex.getMessage(), Duration.seconds(2), NotificationType.ERROR));
}
return null;
}
/**
* Save everything in database
*/
void saveInDataBase(PreparedStatement preparedInsert) {
// Cancelled?
if (isCancelled())
return;
//...
updateProgress(-1, 0);
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
getCancelButton().setDisable(true);
getCancelButton().setText("Saving...");
getInformationTextArea().appendText("Saving...");
latch.countDown();
});
try {
latch.await();
//Insert the remaining
preparedInsert.executeBatch();
// Count how many items where added
//--Below i need to know how many entries have been successfully added [ will be implemented better soon... :) ]
// setTotalInDataBase((int) (getTotalInDataBase()
// + Arrays.stream(preparedInsert.executeBatch()).filter(s -> s > 0).count()))
final CountDownLatch latch2 = new CountDownLatch(1);
Platform.runLater(() -> {
setTotalInDataBase(0);
latch2.countDown();
});
latch2.await();
// Platform.runLater(() -> updateTotalLabel())
} catch (SQLException | InterruptedException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
/**
* Count files in a directory (including files in all sub
* directories)
*
* @param directory
* the directory to start in
* @return the total number of files
*/
int countFiles(File dir) {
int[] count = { 0 };
if (dir.exists())
// try (Stream<Path> paths = Files.walk(Paths.get(dir.getPath()), FileVisitOption.FOLLOW_LINKS)) {
// return (int) paths.filter(path -> {
//
// //Check if cancelled
// if (!isCancelled())
// return InfoTool.isAudioSupported(path + "");
//
// //If it has been cancelled return false
// paths.close();
//
// return false;
// }).count();
// } catch (IOException ex) {
// Main.logger.log(Level.WARNING, "", ex);
// }
try {
Files.walkFileTree(Paths.get(dir.getPath()), new HashSet<FileVisitOption>(Arrays.asList(FileVisitOption.FOLLOW_LINKS)),
Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file , BasicFileAttributes attrs) throws IOException {
if (InfoTool.isAudioSupported(file + ""))
++count[0];
return isCancelled() ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file , IOException e) throws IOException {
System.err.printf("Visiting failed for %s\n", file);
return FileVisitResult.SKIP_SUBTREE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir , BasicFileAttributes attrs) throws IOException {
return isCancelled() ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Total Files=" + count[0]);
return count[0];
}
/**
* Insert this song into the dataBase table
*
* @param path
* @param stars
* @param timesPlayed
* @param dateCreated
* @param hourCreated
*/
void insertMedia(String path , double stars , int timesPlayed , String dateCreated , String hourCreated ,
PreparedStatement preparedInsert) {
try {
if (dateCreated == null || hourCreated == null)
try {
throw new Exception("DATE OR HOUR CREATED ARE NULL [LIBRARY INSERT SONG!]");
} catch (Exception e) {
e.printStackTrace();
}
// Save the Song in the appropriate database table
preparedInsert.setString(1, path);
preparedInsert.setDouble(2, stars);
preparedInsert.setInt(3, timesPlayed);
preparedInsert.setString(4, dateCreated);
preparedInsert.setString(5, hourCreated);
preparedInsert.addBatch();
// if (uInsertIntoLib.executeUpdate() > 0 ? true :
// false)
// updateTotalSongs(++totalSongs, false, false);
// if (sInsert.executeUpdate() > 0)
// ++controller.totalInDataBase;
} catch (SQLException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
};
}
}
}